package automaton.rule;

import automaton.view.BooleanMatrix;

/**
 * Aplica a regra 54 no automato celular de uma dimensao.
 * Deve ser passado por parametro a matriz da evolucao temporal dos automatos.
 * @author Grupo 6
 */
public class AutomatoCelularRegra169 extends AutomatoCelularRegra {

	/**
	 * Construtor herdado.
	 * @param matrizTemporalAutomatos
	 */
	public AutomatoCelularRegra169(BooleanMatrix matrizTemporalAutomatos) {
		super(matrizTemporalAutomatos);
	}
	
	/**
	 * Execucao da regra 54 na matriz de automatos que e atributo desta classe.
	 * Modifica os estados dos automatos de acordo com a regra comum e cria a nova geracao.
	 * 
	 * Funcao de transicao de geracao do automato de acordo com regra padrao 169.
	 * Informacoes sobre a regra podem ser obtidas no endereco http://mathworld.wolfram.com/Rule169.html.
	 */
	public void incrementarGeracao() {
		boolean lGeracaoAtual[] = this.getMatrizTemporalAutomatos().getLastRow(),
				lNovaGeracao[] = lGeracaoAtual.clone(),
				lAutomatoAnterior, 
				lProximoAutomato, 
				lAutomato;
		int lContador;
		
		// Passando por cada um dos automatos e atualizando o resultado sendo que
		// O anterior do primeiro eh o ultimo e o proximo do ultimo eh o primeiro (circular)
		for(lContador=0;lContador < (this.getTamanhoAutomato()); lContador++)
		{
			lAutomato = lGeracaoAtual[lContador];
			
			// Excecao para o primeiro
		  	if(lContador==0)
		  	{
		  		lAutomatoAnterior = lGeracaoAtual[this.getTamanhoAutomato()-1];
		  	} else {
		  		lAutomatoAnterior = lGeracaoAtual[lContador-1];
		  	}
		  	
		  	// Excecao para o ultimo
		  	if(lContador == this.getTamanhoAutomato()-1)
		  	{
		  		lProximoAutomato = lGeracaoAtual[0];
		  	} else {
		  		lProximoAutomato = lGeracaoAtual[lContador+1];
		  	}
		  	
		  	
		  	// Combinacao da vizinhanca de 3 em blocos de condicao encadeados

		  	// Anterior Ligado
		  	if(lAutomatoAnterior)
		  	{
		  		lNovaGeracao[lContador] = lProximoAutomato;
		  		
		  	// Anterior Desligado
		  	} else {
		  		// Proprio ligado
		  		if(lAutomato)
		  		{
		  			lNovaGeracao[lContador] = lProximoAutomato;
		  		// Proprio Desligado
		  		} else {
		  			lNovaGeracao[lContador] = !lProximoAutomato;
		  		}
		  	}
		  	
		}
		try
		{
			this.getMatrizTemporalAutomatos().addRow(lNovaGeracao);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Descricao da regra
	 */
	public String toString()
	{
		return "Regra 169";
	}

}
